package com.bianqian.demo.service;

import com.bianqian.demo.dto.NoteDto;
import com.bianqian.demo.entity.Category;
import com.bianqian.demo.entity.Note;
import com.bianqian.demo.repository.CategoryRepository;
import com.bianqian.demo.repository.NoteRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 分类服务层
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CategoryService {
    
    private final CategoryRepository categoryRepository;
    private final NoteRepository noteRepository;
    
    /**
     * 获取用户的所有分类
     * @param userId 用户ID
     * @return 分类列表
     */
    public List<Category> getCategoriesByUserId(Long userId) {
        log.info("获取用户分类列表，用户ID：{}", userId);
        return categoryRepository.findByUserIdOrderByCreatedAtDesc(userId);
    }
    
    /**
     * 创建分类
     * @param userId 用户ID
     * @param name 分类名称
     * @return 创建的分类
     */
    @Transactional
    public Category createCategory(Long userId, String name) {
        log.info("创建分类，用户ID：{}，分类名称：{}", userId, name);
        
        // 检查分类名称是否已存在
        if (categoryRepository.existsByUserIdAndName(userId, name)) {
            log.warn("分类名称已存在，用户ID：{}，分类名称：{}", userId, name);
            throw new RuntimeException("分类名称已存在");
        }
        
        // 创建新分类
        Category category = new Category();
        category.setUserId(userId);
        category.setName(name.trim());
        category.setCount(0);
        
        Category savedCategory = categoryRepository.save(category);
        log.info("分类创建成功，ID：{}", savedCategory.getId());
        
        return savedCategory;
    }
    
    /**
     * 更新分类
     * @param userId 用户ID
     * @param categoryId 分类ID
     * @param newName 新分类名称
     * @return 更新后的分类
     */
    @Transactional
    public Category updateCategory(Long userId, Long categoryId, String newName) {
        log.info("更新分类，用户ID：{}，分类ID：{}，新名称：{}", userId, categoryId, newName);
        
        // 查找分类
        Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
        if (!categoryOpt.isPresent()) {
            log.warn("分类不存在，ID：{}", categoryId);
            throw new RuntimeException("分类不存在");
        }
        
        Category category = categoryOpt.get();
        
        // 检查是否是用户自己的分类
        if (!category.getUserId().equals(userId)) {
            log.warn("无权限修改分类，用户ID：{}，分类ID：{}", userId, categoryId);
            throw new RuntimeException("无权限修改此分类");
        }
        
        // 检查新名称是否已存在（排除当前分类）
        if (!newName.trim().equals(category.getName()) && 
            categoryRepository.existsByUserIdAndName(userId, newName.trim())) {
            log.warn("分类名称已存在，用户ID：{}，分类名称：{}", userId, newName);
            throw new RuntimeException("分类名称已存在");
        }
        
        // 更新分类名称
        category.setName(newName.trim());
        Category updatedCategory = categoryRepository.save(category);
        
        log.info("分类更新成功，ID：{}", updatedCategory.getId());
        return updatedCategory;
    }
    
    /**
     * 删除分类
     * @param userId 用户ID
     * @param categoryId 分类ID
     */
    @Transactional
    public void deleteCategory(Long userId, Long categoryId) {
        log.info("删除分类，用户ID：{}，分类ID：{}", userId, categoryId);
        
        // 查找分类
        Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
        if (!categoryOpt.isPresent()) {
            log.warn("分类不存在，ID：{}", categoryId);
            throw new RuntimeException("分类不存在");
        }
        
        Category category = categoryOpt.get();
        
        // 检查是否是用户自己的分类
        if (!category.getUserId().equals(userId)) {
            log.warn("无权限删除分类，用户ID：{}，分类ID：{}", userId, categoryId);
            throw new RuntimeException("无权限删除此分类");
        }
        
        // 检查分类下是否还有笔记
        Long noteCount = noteRepository.countByCategoryId(categoryId);
        if (noteCount > 0) {
            log.warn("分类下还有笔记，无法删除，分类ID：{}，笔记数量：{}", categoryId, noteCount);
            throw new RuntimeException("分类下还有笔记，无法删除");
        }
        
        // 删除分类
        categoryRepository.deleteById(categoryId);
        log.info("分类删除成功，ID：{}", categoryId);
    }
    
    /**
     * 获取分类详情（包含笔记列表）
     * @param userId 用户ID
     * @param categoryId 分类ID
     * @return 分类详情
     */
    public Category getCategoryDetail(Long userId, Long categoryId) {
        log.info("获取分类详情，用户ID：{}，分类ID：{}", userId, categoryId);
        
        Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
        if (!categoryOpt.isPresent()) {
            log.warn("分类不存在，ID：{}", categoryId);
            throw new RuntimeException("分类不存在");
        }
        
        Category category = categoryOpt.get();
        
        // 检查是否是用户自己的分类
        if (!category.getUserId().equals(userId)) {
            log.warn("无权限查看分类，用户ID：{}，分类ID：{}", userId, categoryId);
            throw new RuntimeException("无权限查看此分类");
        }
        
        return category;
    }
    
    /**
     * 更新分类统计
     * @param userId 用户ID
     * @param categoryId 分类ID
     * @param operation 操作类型：add/remove
     * @return 更新后的分类
     */
    @Transactional
    public Category updateCategoryCount(Long userId, Long categoryId, String operation) {
        log.info("更新分类统计，用户ID：{}，分类ID：{}，操作：{}", userId, categoryId, operation);
        
        Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
        if (!categoryOpt.isPresent()) {
            log.warn("分类不存在，ID：{}", categoryId);
            throw new RuntimeException("分类不存在");
        }
        
        Category category = categoryOpt.get();
        
        // 检查是否是用户自己的分类
        if (!category.getUserId().equals(userId)) {
            log.warn("无权限更新分类统计，用户ID：{}，分类ID：{}", userId, categoryId);
            throw new RuntimeException("无权限更新此分类统计");
        }
        
        // 更新统计数量
        int currentCount = category.getCount();
        if ("add".equals(operation)) {
            category.setCount(currentCount + 1);
        } else if ("remove".equals(operation) && currentCount > 0) {
            category.setCount(currentCount - 1);
        }
        
        Category updatedCategory = categoryRepository.save(category);
        log.info("分类统计更新成功，ID：{}，新数量：{}", updatedCategory.getId(), updatedCategory.getCount());
        
        return updatedCategory;
    }
    
    /**
     * 重新计算分类统计
     * @param categoryId 分类ID
     */
    @Transactional
    public void recalculateCategoryCount(Long categoryId) {
        log.info("重新计算分类统计，分类ID：{}", categoryId);
        
        Long actualCount = noteRepository.countByCategoryId(categoryId);
        categoryRepository.updateCount(categoryId, actualCount.intValue());
        
        log.info("分类统计重新计算完成，分类ID：{}，实际数量：{}", categoryId, actualCount);
    }
    
    /**
     * 获取分类下的笔记列表
     * @param userId 用户ID
     * @param categoryId 分类ID
     * @return 笔记列表
     */
    public List<NoteDto> getNotesByCategory(Long userId, Long categoryId) {
        log.info("获取分类笔记列表，用户ID：{}，分类ID：{}", userId, categoryId);
        
        try {
            // 验证分类是否存在且属于当前用户
            Optional<Category> categoryOpt = categoryRepository.findById(categoryId);
            if (!categoryOpt.isPresent()) {
                log.warn("分类不存在，ID：{}", categoryId);
                throw new RuntimeException("分类不存在");
            }
            
            Category category = categoryOpt.get();
            log.info("找到分类：{}，用户ID：{}", category.getName(), category.getUserId());
            
            if (!category.getUserId().equals(userId)) {
                log.warn("无权限查看分类笔记，用户ID：{}，分类ID：{}，分类所属用户：{}", userId, categoryId, category.getUserId());
                throw new RuntimeException("无权限查看此分类的笔记");
            }
            
            // 获取分类下的笔记
            log.info("开始查询分类下的笔记，用户ID：{}，分类ID：{}", userId, categoryId);
            List<Note> notes = noteRepository.findByUserIdAndCategoryIdAndIsDeletedFalseOrderByCreatedAtDesc(userId, categoryId);
            log.info("查询到笔记数量：{}", notes.size());
            
            // 转换为DTO
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm");
            List<NoteDto> noteDtos = notes.stream()
                    .map(note -> {
                        NoteDto dto = new NoteDto();
                        dto.setId(note.getId());
                        dto.setUserId(note.getUserId());
                        dto.setCategoryId(note.getCategoryId());
                        dto.setCategoryName(category.getName());
                        dto.setTitle(note.getTitle());
                        dto.setContent(note.getContent());
                        dto.setIsFavorite(note.getIsFavorite());
                        dto.setIsPinned(note.getIsPinned());
                        dto.setIsEncrypted(note.getIsEncrypted());
                        dto.setEncryptedTime(note.getEncryptedTime());
                        dto.setDate(note.getCreatedAt().format(formatter));
                        dto.setCreatedAt(note.getCreatedAt());
                        dto.setUpdatedAt(note.getUpdatedAt());
                        return dto;
                    })
                    .collect(Collectors.toList());
            
            log.info("分类笔记列表获取成功，用户ID：{}，分类ID：{}，笔记数量：{}", userId, categoryId, noteDtos.size());
            return noteDtos;
            
        } catch (RuntimeException e) {
            log.error("获取分类笔记列表失败，用户ID：{}，分类ID：{}，错误：{}", userId, categoryId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("获取分类笔记列表异常，用户ID：{}，分类ID：{}，错误：", userId, categoryId, e);
            throw new RuntimeException("获取分类笔记列表失败：" + e.getMessage());
        }
    }
}
